﻿using com.iot.core.boot;
using com.iot.core.boot.configuration;
using com.iot.core.data;
using com.iot.core.exception;
using com.iot.core.infrastructure;
using com.iot.core.manager.id;
using com.iot.core.util;
using com.iot.ht.Controllers.htsoft.data;
using Microsoft.EntityFrameworkCore;
using NLog;
using System.Linq.Dynamic;
namespace com.iot.ht.Controllers.htsoft.service
{
    public class HtSoftService : BackgroundService
    {
        ILogger<HtSoftService> log;
         
        IRepository<HtSoftApp> baseMapper;
        int RunTimes = 0;
        List<HtSoftLog> lstHtSoftLog=new List<HtSoftLog>();         
        HtSoftCfg htSoftCfg;
        Sms sms;

        public List<HtSoftAppStateDto> Apps { get; private set; } 

        public List<HtSoftApp> HtSoftApps { get
            {
                return Apps.Select(a=>a.HtSoftApp).ToList();    
            } 
        }
        public HtSoftService(ILogger<HtSoftService> log )
        {
            this.log = log;
             
            
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            
            while (!stoppingToken.IsCancellationRequested)
            {
                try {

                    
                    if (RunTimes == 0)
                    {
                        await Task.Delay(3000);//延迟启动 
                        log.LogInformation("监控主程序启动....");                        
                        Singleton<HtSoftService>.Instance = this;
                        htSoftCfg = Singleton<AppSettings>.Instance.Get<HtSoftCfg>();

                        //要手动创建工厂
                        var fact = EngineContext.Current.Resolve<IDbContextFactory<IotDbContext>>();
                        var db = fact.CreateDbContext();
                        baseMapper = new Repository<HtSoftApp>(db);

                         
                        AddLog($"监控程序启动 DB:");
                    }
                     
                    if (Apps == null)
                    {
                        LoadDb();
                    }

                    //启动 
                    foreach (var m in Apps)
                    {
                        if (!m.Started && m.NeedStart)
                        {
                            try
                            {
                                var r = await StartApp(m);
                            }
                            catch (Exception ex)
                            {
                                log.LogError("启动错误：" + ex.Message ?? "");
                            }
                        }
                    }

                    //检查
                    foreach (var m in Apps)
                    {
                        try
                        {
                            if (!m.Started)
                            {
                                continue;
                            }
                            if (    (DateTime.Now >m.NextCkDt) && m.AppCheck != null
                                  )
                            {
                                await CheckApp(m);
                            }  
                        }
                        catch (Exception ex)
                        {
                            log.LogError("检查错误：" + ex.Message ?? "");
                        }
 
                    }

                    RunTimes++;
                    if (RunTimes % 600 == 0)
                    {
                        DeleteLog();
                    }
                    SaveLog();

                    await Task.Delay(5000);

                }
                catch(Exception ex2)
                {
                    log.LogError("ExecuteAsync：" + ex2.Message ?? "");
                } 
            }
            AddLog("监控程序停止");
            log.LogInformation("监控主程序停止");
            foreach (var m in Apps)
            {
                StopApp(m);
            }
            SaveLog();
        }
        void LoadDb()
        {
            var l = new List<HtSoftAppStateDto>();
            baseMapper.GetAll()
                .AsNoTracking()
                .Where(a=>a.HostId==htSoftCfg.HostId)
                .OrderBy(a => a.Sortno)
                .ToList()
                .ForEach(m =>
                {
                    var mm = CreateHtSoftAppStateDto(m);
                    l.Add(mm);

                });
            Apps = l;
        }
        async Task<MyApiResult> StartApp(HtSoftAppStateDto mm)
        {
          
            var r = new MyApiResult();
            if (mm.Started)
            {
                return r;
            }
            
            mm.AppCheck = CreateAppCheck(mm.HtSoftApp);
            mm.AppStart = CreateAppStart(mm.HtSoftApp);
            //var r2 =await mm.AppCheck.Check();
            

            //mm.CkResult = r2.Code == 0;
            //mm.CkMsg = r2.Msg;
            
            //if (r2.Code == 0)
            //{
            //    mm.CkDt = DateTime.Now;
            //    mm.NextCkDt = DateTime.Now.AddSeconds(mm.HtSoftApp.CkInterval);
            //    mm.Started = true;
            //    return r;                
            //}
            r=await mm.AppStart.Start();
            
            if (r.Code == 0)
            {
                mm.Started = true;
                mm.NextCkDt = DateTime.Now.AddMilliseconds(mm.HtSoftApp.StartWaitMs); 
                AddLog(mm.HtSoftApp, "启动成功 "+ mm.NextCkDt.ToString(DateUtil.DateFormatString) );
                 
            }
            else
            {
                mm.CkDt = new DateTime(2020, 01, 01);
                mm.CkResult = false;
                AddLog(mm.HtSoftApp, "启动失败："+r.Msg);
            }

            
            return r;
        }
        MyApiResult StopApp(HtSoftAppStateDto mm)
        {
            var r = new MyApiResult();
            mm.Started = false;
            mm.AppStart = null;
            mm.AppCheck = null;
            mm.CkDt = DateTime.Parse("2020-01-01");
            mm.CkResult = false;
            mm.CkMsg = "";
            AddLog(mm.HtSoftApp, "停止：" + r.Msg);

            return r;
        }
        async Task<MyApiResult> StopAppEx(HtSoftAppStateDto mm)
        {
            var r = new MyApiResult();

            if (mm.AppStart != null)
            {
                await mm.AppStart.StopEx();
            }
            mm.Started = false;
            mm.AppStart = null;
            mm.AppCheck = null;
            mm.CkDt = DateTime.Parse("2020-01-01");
            mm.CkResult = false;
            mm.CkMsg = "";
            AddLog(mm.HtSoftApp, "强制停止：" + r.Msg);

            return r;
        }


        async Task<MyApiResult> CheckApp(HtSoftAppStateDto mm)
        {
            
            var m = mm;
            var r = await m.AppStart.Check();
            switch (r.Code)
            {
                case 1:
                    AddLog(m.HtSoftApp, "检查异常:" + r.Msg);
                    return r; 
                case 2:
                    await StopAppEx(m);
                    AddLog(m.HtSoftApp, "检查重启:" + r.Msg);
                    return r; 
                default:
                    break;
            }

            r = await m.AppCheck.Check();
            m.CkDt = DateTime.Now;
            mm.NextCkDt = DateTime.Now.AddSeconds(mm.HtSoftApp.CkInterval);
             
            if (r.Code == 0)
            {
                //成功
                m.CkResult = true;
                m.CkMsg = r.Msg;
                m.CkFailTimes = 0;
            }
            else if (r.Code == 1)
            {
                //失败
                m.CkResult = false;
                m.CkMsg = r.Msg;
                m.CkFailTimes++;
                if (m.HtSoftApp.CkFailRestar != 0 && m.HtSoftApp.CkFailRestar == m.CkFailTimes)
                {
                    await StopAppEx(m);
                }

                if (m.HtSoftApp.CkFailSms != 0 && m.HtSoftApp.CkFailSms == m.CkFailTimes)
                {
                    await SendSms(m.HtSoftApp, $"{m.HtSoftApp.Name} {m.CkFailTimes}次 检测失败");
                } 
            } 

            AddLog(m.HtSoftApp, r.Msg);
            return r;
             
        }
       
        

        AppCheck CreateAppCheck(HtSoftApp mm)
        {            
            var clsname= "com.iot.ht.Controllers.htsoft.service.AppCheck"+mm.CkMethod;
            var t = Type.GetType(clsname);
            if (t == null)
            {
                return new AppCheckOther();
            }
            var r = Activator.CreateInstance(t) as AppCheck; // 通过Activator.CreateInstance方法创建对象
            r.HtSoftApp = mm;
            return r;
        }

        AppStart CreateAppStart(HtSoftApp mm)
        {
            var clsname = "com.iot.ht.Controllers.htsoft.service.AppStart" + mm.Lx;
            var t = Type.GetType(clsname);
            if (t == null)
            {
                return new  AppStartOther(); ;
            }
            var r = Activator.CreateInstance(t) as AppStart; // 通过Activator.CreateInstance方法创建对象
            r.HtSoftApp = mm;
            return r;
        }
        HtSoftAppStateDto CreateHtSoftAppStateDto(HtSoftApp mm)
        {
            var m = new HtSoftAppStateDto
            {
                Id = mm.Id,
                Name = mm.Name,
                AppCheck =null,
                AppStart = null,
                HtSoftApp = mm,
                Started = false,
                CkDt = DateTime.Parse("2020-01-01"),
                CkMsg = "",
                CkResult = false,
                NeedStart=mm.AutoStart
            };
            return m;
        }



        #region 数据操作
        public int Insert(HtSoftApp mm)
        {
           
            var mold = Apps.Where(a => a.Id == mm.Id).FirstOrDefault();
            if (mold != null)
            {
                throw new MyException("编号重复");
            }
            mold = Apps.Where(a => a.Name == mm.Name).FirstOrDefault();
            if (mold != null)
            {
                throw new MyException("名称重复");
            }
            mm.HostId = htSoftCfg.HostId;
            baseMapper.Insert(mm, true);
            var r= baseMapper.SaveChagnes();
            baseMapper.DB.ChangeTracker.Clear();
            var mdto = CreateHtSoftAppStateDto(mm);
            Apps.Add(mdto);
            return r;
        }
        public int Update(HtSoftApp mm)
        {
            var mold = Apps.Where(a => a.Id == mm.Id).FirstOrDefault();
            if (mold == null)
            {
                throw new MyException("数据错误");
            }

            var moldApp = Apps.Where(a => a.Id == mm.Id).FirstOrDefault();
            if (moldApp.Started)
            {
                throw new MyException("正在运行，不能修改");
            }
             
            if (mold.Name!=mm.Name) {

                mold = Apps.Where(a => a.Name == mm.Name).FirstOrDefault();
                if (mold != null)
                {
                    throw new MyException("名称重复");
                }
            } 
            baseMapper.Update(mm, true);
            var r=baseMapper.SaveChagnes();
            baseMapper.DB.ChangeTracker.Clear();
            moldApp.Name = mm.Name;
            moldApp.HtSoftApp = mm;
            return r;
        }

        public int Delete(BaseQto mm)
        {
             
            var moldApp = Apps.Where(a => a.Id == mm.Id).FirstOrDefault();
            if (moldApp.Started)
            {
                throw new MyException("正在运行，不能删除");
            }

            baseMapper.Delete(moldApp.HtSoftApp);
            baseMapper.SaveChagnes();
            baseMapper.DB.ChangeTracker.Clear();
            Apps.Remove(moldApp);
            return 1;
        }

        public async Task<int> StartSingleApp(BaseQto mm)
        {
            var mold = Apps.Where(a => a.Id == mm.Id).FirstOrDefault();          
            mold.NeedStart=true;
            await Task.Delay(2000);
            return 1;
        }
        public int StopSingleApp(BaseQto mm)
        {
            var mold = Apps.Where(a => a.Id == mm.Id).FirstOrDefault();
            mold.NeedStart = false;
            StopApp(mold);           
            return 1;
        }
        public int StopSingleAppEx(BaseQto mm)
        {
            var mold = Apps.Where(a => a.Id == mm.Id).FirstOrDefault();
            mold.NeedStart = false;
            StopAppEx(mold);            
            return 1;
        }
        #endregion

        #region 日志
        public void AddLog( string msg)
        {
            var m = new HtSoftLog
            {
                Id = HtIdManager.Current.NextLong(),
                CrtDt = DateTime.Now,
                HostId = htSoftCfg.HostId,
                HtsoftappId = 0,
                HtsoftappName = "主程序",
                Msg = msg
            };
            lstHtSoftLog.Add(m);
        }

        public void AddLog(HtSoftApp mm ,string msg)
        {
            var m = new HtSoftLog
            {
                Id=HtIdManager.Current.NextLong(),
                CrtDt=DateTime.Now,
                HostId= htSoftCfg.HostId,
                HtsoftappId=mm.Id,
                HtsoftappName=mm.Name,
                Msg=msg 
            };
            lstHtSoftLog.Add(m);
        }
        void SaveLog()
        {
            if (lstHtSoftLog.Count == 0)
            {
                return;
            }
            baseMapper.DB.AddRange(lstHtSoftLog);
            baseMapper.SaveChagnes();
            lstHtSoftLog.Clear();
        }

        void DeleteLog()
        {
            log.LogInformation("删除日志开始");
            var tid = HtIdManager.Current.DateToLongID(DateTime.Now.Date.AddDays(-3));
            var sql = $"delete from HtSoftLog where  id<{tid};select 1 as id,'a' as Name;";
            baseMapper.QueryToList<IdNameDto>(sql,30);
            log.LogInformation("删除日志结束");

        }
        #endregion

        #region 短信
        public async Task SendSms(  string msg)
        {
            if (string.IsNullOrWhiteSpace(htSoftCfg.SmsMobiles))
            {
                return;
            }
            if (sms == null)
            {
                var clsName = "com.iot.ht.Controllers.htsoft.service.Sms" + htSoftCfg.SmsLx;
                var type = Type.GetType(clsName);
                if (type != null)
                {
                    sms = Activator.CreateInstance(type) as Sms;
                    sms.SmsCfg = htSoftCfg.SmsCfg;
                }
            }
            var msg2 = msg;
            var rmsg = await sms.SendAsync(htSoftCfg.SmsMobiles, new List<string> { msg2 });
            AddLog( "发送短信：" + rmsg);
        }

        public async Task SendSms(HtSoftApp mm,string msg)
        { 
            if (string.IsNullOrWhiteSpace(htSoftCfg.SmsMobiles))
            {
                return;
            }
            if (sms == null)
            {
                var clsName = "com.iot.ht.Controllers.htsoft.service.Sms" + htSoftCfg.SmsLx;
                var type = Type.GetType(clsName);
                if (type != null)
                {
                    sms = Activator.CreateInstance(type) as Sms;
                    sms.SmsCfg = htSoftCfg.SmsCfg;
                }
            }
            var msg2 = $"{mm.Name}:{msg}";
            var rmsg=await sms.SendAsync(htSoftCfg.SmsMobiles, new List<string> { msg2});
            AddLog(mm, "发送短信：" + rmsg);
        }
        #endregion
    }
}
